﻿using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StepsManagerLibrary;
using StepsManagerLibrary.Interfaces;

namespace StepsManagerTest
{
    [TestClass]
    public class BaseStepsManagerTest
    {
        #region Constructors

        /// <summary>
        /// Class defined to test the base methods of the BaseStepManager
        /// </summary>
        private class TestBaseStepManager : BaseStepManager<string>
        {
            public override bool GoToFirst()
            {
                throw new System.NotImplementedException();
            }
            public override bool GoToLast()
            {
                throw new System.NotImplementedException();
            }
            public override bool GoToPrevious()
            {
                throw new System.NotImplementedException();
            }
            public override bool GoToNext()
            {
                throw new System.NotImplementedException();
            }
            public override bool GoTo(string step)
            {
                throw new System.NotImplementedException();
            }
        }

        // Simple constructor of a StepsManager, testing Steps value
        [TestMethod]
        [TestCategory("Constructor"), TestCategory("Steps")]
        public void Constructor1_EmptyStepManager_StepsValue()
        {
            IStepManager<string> stepManager = new TestBaseStepManager();

            Assert.AreNotEqual(stepManager.Steps, null);

            if (stepManager.Steps != null)
                Assert.AreEqual(stepManager.Steps.Count, 0);
        }

        // Simple constructor of a StepManager, testing CurrentStep value
        [TestMethod]
        [TestCategory("Constructor"), TestCategory("CurrentStep")]
        public void Constructor2_EmptyStepManager_CurrentStepValue()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();

            Assert.AreEqual(stepManager.CurrentStep, null);
        }

        #endregion

        #region Steps { get; set; }

        // Steps null assignment
        [TestMethod]
        [TestCategory("Steps"), TestCategory("CurrentStep")]
        public void Steps_SetWithNull()
        {
            IStepManager<string> stepManager = new TestBaseStepManager();
            stepManager.Steps = null;

            Assert.AreNotEqual(stepManager.Steps, null);
            Assert.AreEqual(stepManager.CurrentStep, null);

            if (stepManager.Steps != null)
                Assert.AreEqual(stepManager.Steps.Count, 0);
        }

        // Steps 1 element assignment
        [TestMethod]
        [TestCategory("Steps"), TestCategory("CurrentStep")]
        public void Steps_SetWith1Element_Value()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step1" };

            Assert.AreNotEqual(stepManager.Steps, null);
            Assert.AreEqual(stepManager.CurrentStep, "step1");

            Assert.AreEqual(stepManager.Steps.Count, 1);
            Assert.AreEqual(stepManager.Steps[0], "step1");
        }

        // Steps 2 elements assignment
        [TestMethod]
        [TestCategory("Steps"), TestCategory("CurrentStep")]
        public void Steps_SetWith2Elements_Value()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step1", "step2" };

            Assert.AreNotEqual(stepManager.Steps, null);
            Assert.AreEqual(stepManager.CurrentStep, "step1");

            Assert.AreEqual(stepManager.Steps.Count, 2);
            Assert.AreEqual(stepManager.Steps[0], "step1");
            Assert.AreEqual(stepManager.Steps[1], "step2");
        }

        // Steps multiple assignment
        [TestMethod]
        [TestCategory("Steps"), TestCategory("Next"), TestCategory("CurrentStep")]
        public void Steps_SetWith2Elements_CurrentValueUpdate()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step0", "step2" };

            Assert.AreNotEqual(stepManager.Steps, null);
            Assert.AreEqual(stepManager.CurrentStep, "step0");

            stepManager.Steps = new List<string>() { "step1", "step2" };
            Assert.AreEqual(stepManager.CurrentStep, "step1");

            Assert.AreEqual(stepManager.Steps.Count, 2);
            Assert.AreEqual(stepManager.Steps[0], "step1");
            Assert.AreEqual(stepManager.Steps[1], "step2");
        }

        #endregion

        #region InsertStepAt

        // Basic InsertStepAt
        [TestMethod]
        [TestCategory("InsertStepAt")]
        public void InsertStepAt_Success()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step1", "step3" };
            bool stepInsertResult = stepManager.InsertStepAt("step2", 1);

            if (stepManager.Steps != null)
            {
                Assert.AreEqual(stepInsertResult, true);
                Assert.AreEqual(stepManager.Steps.Count, 3);
                Assert.AreEqual(stepManager.Steps[0], "step1");
                Assert.AreEqual(stepManager.Steps[1], "step2");
                Assert.AreEqual(stepManager.Steps[2], "step3");
            }
        }

        // InsertStepAt the CurrentStep position
        [TestMethod]
        [TestCategory("InsertStepAt"), TestCategory("CurrentStep")]
        public void InsertStepAt_Success_CurrentStep()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step2", "step3" };

            Assert.AreEqual("step2", stepManager.CurrentStep);

            // Inserting an element at the position of the CurrentStep
            // This should not imply that the CurrentStep changes
            bool stepInsertResult = stepManager.InsertStepAt("step1", 0);
            Assert.AreEqual("step2", stepManager.CurrentStep);

            Assert.AreEqual(stepInsertResult, true);
            Assert.AreEqual(stepManager.Steps.Count, 3);
            Assert.AreEqual(stepManager.Steps[0], "step1");
            Assert.AreEqual(stepManager.Steps[1], "step2");
            Assert.AreEqual(stepManager.Steps[2], "step3");
        }

        // InsertStepAt a step that already exist in the step collection
        [TestMethod]
        [TestCategory("InsertStepAt"), TestCategory("StepAlreadyExist")]
        public void InsertStepAt_Failure_InsertingTheSameStep()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step2", "step3" };

            Assert.AreEqual("step2", stepManager.CurrentStep);

            // Inserting an element that already exist
            bool stepInsertResult = stepManager.InsertStepAt("step2", 0);
            Assert.AreEqual("step2", stepManager.CurrentStep);

            Assert.AreEqual(stepInsertResult, false);
            Assert.AreEqual(stepManager.Steps.Count, 2);
            Assert.AreEqual(stepManager.Steps[0], "step2");
            Assert.AreEqual(stepManager.Steps[1], "step3");
        }

        // InsertStepAt a negative position
        [TestMethod]
        [TestCategory("InsertStepAt")]
        public void InsertStepAt_Failure_NegativePosition()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step1", "step3" };
            bool stepInsertResult = stepManager.InsertStepAt("step2", -5);

            Assert.AreEqual(stepInsertResult, false);
            Assert.AreEqual(stepManager.Steps.Count, 2);
            Assert.AreEqual(stepManager.Steps[0], "step1");
            Assert.AreEqual(stepManager.Steps[1], "step3");
        }

        // InsertStepAt a position that is out of bond
        [TestMethod]
        [TestCategory("InsertStepAt")]
        public void InsertStepAt_Failure_OutOfBoundPosition()
        {
            IStepManager<string> stepManager= new TestBaseStepManager();
            stepManager.Steps = new List<string>() { "step1", "step3" };
            bool stepInsertResult = stepManager.InsertStepAt("step2", 5);

            Assert.AreEqual(stepInsertResult, false);
            Assert.AreEqual(stepManager.Steps.Count, 2);
            Assert.AreEqual(stepManager.Steps[0], "step1");
            Assert.AreEqual(stepManager.Steps[1], "step3");
        }

        #endregion
    }
}
